from django.contrib import messages
from django.contrib.auth import get_user_model, logout
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import LoginView
from django.core.exceptions import PermissionDenied
from django.db.models import Q
from django.http import Http404, HttpRequest, HttpResponse
from django.shortcuts import redirect, render
from django.urls import reverse_lazy
from django.views import View
from django.views.generic import FormView
from django.utils import timezone

from accounts.forms import (
    ProfileForm,
    StudentRegistrationForm,
    TeacherAnnouncementForm,
    TeacherAssignmentForm,
    TeacherStudentLinkForm,
    AssignmentSubmissionForm,
)
from accounts.models import UserNotification
from learning.models import (
    AssignmentSubmission,
    Mistake,
    NotebookEntry,
    TeacherAnnouncement,
    TeacherAssignment,
)


def send_notifications(users, *, title: str, message: str = "", link: str = "", category: str = UserNotification.Category.MESSAGE):
    if not users:
        return
    timestamp = timezone.now()
    notifications = [
        UserNotification(
            user=user,
            title=title,
            message=message,
            link=link,
            category=category,
            created_at=timestamp,
        )
        for user in users
    ]
    UserNotification.objects.bulk_create(notifications)


class MathAssistLoginView(LoginView):
    template_name = "accounts/login.html"
    redirect_authenticated_user = True

    def get_success_url(self):
        return self.get_redirect_url() or reverse_lazy("learning:mistake_list")


class RegisterView(FormView):
    template_name = "accounts/register.html"
    form_class = StudentRegistrationForm
    success_url = reverse_lazy("accounts:login")

    def dispatch(self, request, *args, **kwargs):
        if request.user.is_authenticated:
            return redirect("learning:mistake_list")
        return super().dispatch(request, *args, **kwargs)

    def form_valid(self, form):
        form.save()
        return super().form_valid(form)


class ProfileView(LoginRequiredMixin, View):
    student_template_name = "accounts/profile.html"
    teacher_template_name = "accounts/teacher_profile.html"

    def get(self, request: HttpRequest) -> HttpResponse:
        if getattr(request.user, "is_teacher", False):
            context = self._build_teacher_context(request)
            return render(request, self.teacher_template_name, context)
        form = ProfileForm(instance=request.user)
        context = self._build_student_context(request, form)
        return render(request, self.student_template_name, context)

    def post(self, request: HttpRequest) -> HttpResponse:
        if getattr(request.user, "is_teacher", False):
            return self._handle_teacher_post(request)
        return self._handle_student_post(request)

    def _handle_student_post(self, request: HttpRequest) -> HttpResponse:
        action = request.POST.get("action", "update_profile")
        if action != "update_profile":
            raise PermissionDenied("无权执行此操作。")
        form = ProfileForm(request.POST, instance=request.user)
        if form.is_valid():
            form.save()
            messages.success(request, "个人信息已更新。")
            return redirect("accounts:profile")
        context = self._build_student_context(request, form)
        return render(request, self.student_template_name, context, status=200)

    def _handle_teacher_post(self, request: HttpRequest) -> HttpResponse:
        action = request.POST.get("action")
        if action == "link_student":
            form = TeacherStudentLinkForm(request.POST, teacher=request.user)
            if form.is_valid():
                student = form.save()
                send_notifications(
                    [student],
                    title="已加入新的指导老师",
                    message=f"你现在由 {request.user.get_full_name() or request.user.username} 老师指导。",
                    link=reverse_lazy("accounts:profile"),
                    category=UserNotification.Category.MESSAGE,
                )
                messages.success(request, "已成功关联学生。")
                return redirect("accounts:profile")
            context = self._build_teacher_context(request, student_link_form=form)
            return render(request, self.teacher_template_name, context, status=200)
        if action == "create_announcement":
            form = TeacherAnnouncementForm(request.POST, teacher=request.user)
            if form.is_valid():
                announcement = form.save()
                send_notifications(
                    request.user.students.all(),
                    title="老师发布了新公告",
                    message=announcement.title,
                    link=reverse_lazy("accounts:mailbox"),
                    category=UserNotification.Category.ANNOUNCEMENT,
                )
                messages.success(request, "公告已发布给所有关联学生。")
                return redirect("accounts:profile")
            context = self._build_teacher_context(request, announcement_form=form)
            return render(request, self.teacher_template_name, context, status=200)
        if action == "create_assignment":
            form = TeacherAssignmentForm(request.POST, teacher=request.user)
            if form.is_valid():
                assignment = form.save()
                send_notifications(
                    request.user.students.all(),
                    title="老师布置了新作业",
                    message=assignment.title,
                    link=reverse_lazy("accounts:profile"),
                    category=UserNotification.Category.ASSIGNMENT,
                )
                messages.success(request, "作业已布置给所有关联学生。")
                return redirect("accounts:profile")
            context = self._build_teacher_context(request, assignment_form=form)
            return render(request, self.teacher_template_name, context, status=200)
        if action == "resolve_mistake":
            mistake_id = request.POST.get("mistake_id")
            feedback = request.POST.get("feedback", "").strip()
            try:
                mistake = Mistake.objects.select_related("student").get(pk=mistake_id)
            except Mistake.DoesNotExist as exc:
                raise Http404 from exc
            if mistake.student.assigned_teacher_id != request.user.id:
                raise PermissionDenied
            mistake.resolve(reviewer=request.user, feedback=feedback)
            send_notifications(
                [mistake.student],
                title="错题已批阅",
                message=f"老师给出反馈：{feedback or '请查看详情'}",
                link=mistake.get_absolute_url(),
                category=UserNotification.Category.MESSAGE,
            )
            messages.success(request, "已完成错题批阅。")
            return redirect("accounts:profile")
        if action == "update_profile":
            form = ProfileForm(request.POST, instance=request.user)
            if form.is_valid():
                form.save()
                messages.success(request, "个人信息已更新。")
                return redirect("accounts:profile")
            context = self._build_teacher_context(request, profile_form=form)
            return render(request, self.teacher_template_name, context, status=200)
        raise Http404("无效的操作。")

    def _build_teacher_context(self, request: HttpRequest, **overrides) -> dict:
        teacher = request.user
        profile_form = overrides.get("profile_form") or ProfileForm(instance=teacher)
        student_link_form = overrides.get("student_link_form") or TeacherStudentLinkForm(
            teacher=teacher
        )
        announcement_form = overrides.get("announcement_form") or TeacherAnnouncementForm(
            teacher=teacher
        )
        assignment_form = overrides.get("assignment_form") or TeacherAssignmentForm(
            teacher=teacher
        )
        assigned_students = teacher.students.all().order_by("username")
        announcements = teacher.announcements.all()[:5]
        assignments = teacher.assignments.all()[:5]
        pending_mistakes = (
            Mistake.objects.filter(
                student__assigned_teacher=teacher,
                status=Mistake.Status.SUBMITTED,
                is_archived=False,
            )
            .select_related("student")
            .order_by("-submitted_at", "-updated_at")[:5]
        )
        pending_notes = (
            NotebookEntry.objects.filter(
                student__assigned_teacher=teacher,
                status=NotebookEntry.Status.SUBMITTED,
            )
            .select_related("student")
            .order_by("-submitted_at", "-updated_at")[:5]
        )
        recent_submissions = (
            AssignmentSubmission.objects.filter(assignment__teacher=teacher)
            .select_related("student", "assignment")
            .order_by("-submitted_at")[:5]
        )

        context = {
            "profile_form": profile_form,
            "student_link_form": student_link_form,
            "announcement_form": announcement_form,
            "assignment_form": assignment_form,
            "assigned_students": assigned_students,
            "announcements": announcements,
            "assignments": assignments,
            "pending_mistakes": pending_mistakes,
            "pending_notes": pending_notes,
            "recent_submissions": recent_submissions,
            "role_display": teacher.get_role_display(),
        }

        query = request.GET.get("q", "").strip()
        if query:
            User = get_user_model()
            context["search_query"] = query
            context["search_results"] = (
                User.objects.filter(role=User.Role.STUDENT, username__icontains=query)
                .filter(Q(assigned_teacher__isnull=True) | Q(assigned_teacher=teacher))
                .order_by("username")[:10]
            )
        else:
            context["search_results"] = []

        return context

    def _build_student_context(self, request: HttpRequest, form: ProfileForm) -> dict:
        teacher = getattr(request.user, "assigned_teacher", None)
        announcements = list(teacher.announcements.all()[:5]) if teacher else []
        assignments_qs = teacher.assignments.all() if teacher else TeacherAssignment.objects.none()
        assignments = list(assignments_qs[:5])
        submissions = AssignmentSubmission.objects.filter(
            student=request.user,
            assignment__in=[assignment.id for assignment in assignments],
        )
        submission_map = {submission.assignment_id: submission for submission in submissions}
        assignment_pairs = [
            (assignment, submission_map.get(assignment.id)) for assignment in assignments
        ]
        return {
            "form": form,
            "assigned_teacher": teacher,
            "role_display": request.user.get_role_display(),
            "announcements": announcements[:5],
            "assignment_pairs": assignment_pairs,
        }


class TeacherAnnouncementUpdateView(LoginRequiredMixin, View):
    template_name = "accounts/teacher_announcement_form.html"

    def dispatch(self, request, *args, **kwargs):
        if not getattr(request.user, "is_teacher", False):
            raise PermissionDenied
        return super().dispatch(request, *args, **kwargs)

    def _get_object(self, request: HttpRequest, pk: int) -> TeacherAnnouncement:
        try:
            return request.user.announcements.get(pk=pk)
        except TeacherAnnouncement.DoesNotExist as exc:
            raise Http404 from exc

    def get(self, request: HttpRequest, pk: int) -> HttpResponse:
        announcement = self._get_object(request, pk)
        form = TeacherAnnouncementForm(instance=announcement, teacher=request.user)
        return render(request, self.template_name, {"form": form, "announcement": announcement})

    def post(self, request: HttpRequest, pk: int) -> HttpResponse:
        announcement = self._get_object(request, pk)
        form = TeacherAnnouncementForm(request.POST, instance=announcement, teacher=request.user)
        if form.is_valid():
            form.save()
            messages.success(request, "公告已更新。")
            return redirect("accounts:profile")
        return render(request, self.template_name, {"form": form, "announcement": announcement}, status=200)


class TeacherAnnouncementDeleteView(LoginRequiredMixin, View):
    def dispatch(self, request, *args, **kwargs):
        if not getattr(request.user, "is_teacher", False):
            raise PermissionDenied
        return super().dispatch(request, *args, **kwargs)

    def post(self, request: HttpRequest, pk: int) -> HttpResponse:
        try:
            announcement = request.user.announcements.get(pk=pk)
        except TeacherAnnouncement.DoesNotExist as exc:
            raise Http404 from exc
        announcement.delete()
        messages.success(request, "公告已撤回。")
        return redirect("accounts:profile")


class TeacherAssignmentUpdateView(LoginRequiredMixin, View):
    template_name = "accounts/teacher_assignment_form.html"

    def dispatch(self, request, *args, **kwargs):
        if not getattr(request.user, "is_teacher", False):
            raise PermissionDenied
        return super().dispatch(request, *args, **kwargs)

    def _get_object(self, request: HttpRequest, pk: int) -> TeacherAssignment:
        try:
            return request.user.assignments.get(pk=pk)
        except TeacherAssignment.DoesNotExist as exc:
            raise Http404 from exc

    def get(self, request: HttpRequest, pk: int) -> HttpResponse:
        assignment = self._get_object(request, pk)
        form = TeacherAssignmentForm(instance=assignment, teacher=request.user)
        return render(request, self.template_name, {"form": form, "assignment": assignment})

    def post(self, request: HttpRequest, pk: int) -> HttpResponse:
        assignment = self._get_object(request, pk)
        form = TeacherAssignmentForm(request.POST, instance=assignment, teacher=request.user)
        if form.is_valid():
            form.save()
            messages.success(request, "作业已更新。")
            return redirect("accounts:profile")
        return render(request, self.template_name, {"form": form, "assignment": assignment}, status=200)


class TeacherAssignmentDeleteView(LoginRequiredMixin, View):
    def dispatch(self, request, *args, **kwargs):
        if not getattr(request.user, "is_teacher", False):
            raise PermissionDenied
        return super().dispatch(request, *args, **kwargs)

    def post(self, request: HttpRequest, pk: int) -> HttpResponse:
        try:
            assignment = request.user.assignments.get(pk=pk)
        except TeacherAssignment.DoesNotExist as exc:
            raise Http404 from exc
        assignment.delete()
        messages.success(request, "作业已撤回。")
        return redirect("accounts:profile")


class MailboxView(LoginRequiredMixin, View):
    template_name = "accounts/mailbox.html"

    def get(self, request: HttpRequest) -> HttpResponse:
        notifications = list(request.user.notifications.all())
        unread = [n.pk for n in notifications if n.is_unread]
        if unread:
            request.user.notifications.filter(pk__in=unread).update(read_at=timezone.now())
        return render(
            request,
            self.template_name,
            {"notifications": notifications},
        )


class AssignmentSubmitView(LoginRequiredMixin, View):
    template_name = "accounts/student_assignment_submit.html"

    def dispatch(self, request, *args, **kwargs):
        if not getattr(request.user, "is_student", False):
            raise PermissionDenied
        return super().dispatch(request, *args, **kwargs)

    def _get_assignment(self, request: HttpRequest, pk: int) -> TeacherAssignment:
        try:
            assignment = TeacherAssignment.objects.select_related("teacher").get(pk=pk)
        except TeacherAssignment.DoesNotExist as exc:
            raise Http404 from exc
        teacher = assignment.teacher
        if request.user.assigned_teacher_id != teacher.id:
            raise Http404
        return assignment

    def get(self, request: HttpRequest, pk: int) -> HttpResponse:
        assignment = self._get_assignment(request, pk)
        existing = AssignmentSubmission.objects.filter(
            assignment=assignment, student=request.user
        ).first()
        form = AssignmentSubmissionForm(initial={"content": getattr(existing, "content", "")})
        return render(
            request,
            self.template_name,
            {"form": form, "assignment": assignment, "submission": existing},
        )

    def post(self, request: HttpRequest, pk: int) -> HttpResponse:
        assignment = self._get_assignment(request, pk)
        form = AssignmentSubmissionForm(request.POST)
        if not form.is_valid():
            return render(
                request,
                self.template_name,
                {"form": form, "assignment": assignment},
                status=200,
            )
        submission, created = AssignmentSubmission.objects.update_or_create(
            assignment=assignment,
            student=request.user,
            defaults={"content": form.cleaned_data["content"]},
        )
        send_notifications(
            [assignment.teacher],
            title="作业已提交",
            message=f"{request.user.get_full_name() or request.user.username} 提交了 {assignment.title}",
            link=reverse_lazy("accounts:profile"),
            category=UserNotification.Category.ASSIGNMENT,
        )
        send_notifications(
            [request.user],
            title="作业提交成功",
            message=f"已提交 {assignment.title}",
            link=reverse_lazy("accounts:mailbox"),
            category=UserNotification.Category.ASSIGNMENT,
        )
        messages.success(request, "作业已提交，继续加油！")
        return redirect("accounts:mailbox")


def logout_view(request: HttpRequest) -> HttpResponse:
    logout(request)
    messages.info(request, "你已安全退出。")
    return redirect("accounts:login")
